﻿#include "pch.h"
#include "MainWindow.h"
#include "Resource.h"

BEGIN_MESSAGE_MAP(MainWindow, CDialog)
    ON_COMMAND(IDC_BUTTON_HELP, OnButtonHelpClicked)
    ON_COMMAND(IDC_BUTTON_MUSIC, OnButtonMusicClicked)
    ON_COMMAND(IDC_BUTTON_PAUSE, OnButtonPauseClicked)
    ON_COMMAND(IDC_BUTTON_START, OnButtonStartClicked)
    ON_MESSAGE(Const::UM_DIFFICULTY_UP, OnDifficultyUp)
    ON_MESSAGE(Const::UM_GAME_OVER, OnGameOver)
    ON_MESSAGE(Const::UM_SCORE, OnScore)
    ON_WM_ACTIVATE()
    ON_WM_TIMER()
END_MESSAGE_MAP()

/**
 * 构造方法。
 * @param parent    父窗口
 */
MainWindow::MainWindow(CWnd* parent) :
    CDialog(IDD_MAIN_WINDOW, parent),
    mGame(NULL),
    mGameBoard(Const::GAME_BOARD_WIDTH, Const::GAME_BOARD_HEIGHT) {
}

/**
 * 析构方法。
 */
MainWindow::~MainWindow() {
    // 删除游戏
    delete mGame;
}

/**
 * 窗口活动事件的响应方法。
 * @param state 为 WA_INACTIVE 则表示窗口进入不活动状态
 */
void MainWindow::OnActivate(UINT state, CWnd*, BOOL) {
    Game::Status status = mGame->GetStatus();
    if (status == Game::PLAYING && state == WA_INACTIVE) {
        this->OnButtonPauseClicked();
    }
}

/**
 * "帮助"按钮的单击响应方法。
 */
void MainWindow::OnButtonHelpClicked() {
    AfxMessageBox(IDS_HELP_TEXT, MB_ICONINFORMATION);
}

/**
 * "播放音乐"按钮的单击响应方法。
 */
void MainWindow::OnButtonMusicClicked() {
    BOOL playingMusic = mGame->PlayMusic();
    mToolBar.GetToolBarCtrl().CheckButton(IDC_BUTTON_MUSIC, playingMusic);
}

/**
 * "暂停"按钮的单击响应方法。
 */
void MainWindow::OnButtonPauseClicked() {
    mGame->Pause();
    mToolBar.GetToolBarCtrl().CheckButton(IDC_BUTTON_PAUSE, mGame->GetStatus() == Game::PAUSED);
}

/**
 * "开始"按钮的单击响应方法。
 */
void MainWindow::OnButtonStartClicked() {
    // 游戏开始
    mGame->Start();

    // 设置按钮状态
    mToolBar.GetToolBarCtrl().EnableButton(IDC_BUTTON_PAUSE, TRUE);
    mToolBar.GetToolBarCtrl().CheckButton(IDC_BUTTON_PAUSE, FALSE);

    // 设置状态栏上的文字
    CString text;
    text.LoadString(IDS_DIFFICULTY);
    text += _T("1");
    mStatusBar.SetText(text, 0, 0);

    text.LoadString(IDS_SCORE);
    text += _T("0");
    mStatusBar.SetText(text, 1, 0);
}

/**
 * 难度增加事件的响应方法。
 * @param wParam    难度
 */
LRESULT MainWindow::OnDifficultyUp(WPARAM wParam, LPARAM) {
    CString text;
    CString difficulty;
    text.LoadString(IDS_DIFFICULTY);
    difficulty.Format(_T("%d"), wParam);
    text += difficulty;
    mStatusBar.SetText(text, 1, 0);
    return 0;
}

/**
 * 游戏结束事件的响应方法。
 * @param isWon  胜利则为 TRUE，否则为 FALSE
 * @return 总是零
 */
LRESULT MainWindow::OnGameOver(WPARAM isWon, LPARAM) {
    if (isWon) {
        AfxMessageBox(IDS_WON, MB_ICONINFORMATION);
    } else {
        AfxMessageBox(IDS_LOST, MB_ICONINFORMATION);
    }

    mToolBar.GetToolBarCtrl().CheckButton(IDC_BUTTON_PAUSE, FALSE);
    mToolBar.GetToolBarCtrl().EnableButton(IDC_BUTTON_PAUSE, FALSE);
    return 0;
}

/**
 * 初始化事件的响应方法。
 * @return 总是 TRUE
 */
BOOL MainWindow::OnInitDialog() {
    CDialog::OnInitDialog();

    // 创建工具栏
    DWORD style = WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC;
    mToolBar.CreateEx(this, TBSTYLE_FLAT | TBSTYLE_TOOLTIPS, style);
    CToolBarCtrl& toolBarCtrl = mToolBar.GetToolBarCtrl();

    // 设置工具栏图片尺寸和按钮尺寸
    HINSTANCE instance = AfxGetInstanceHandle();
    HICON icon = LoadIcon(instance, MAKEINTRESOURCE(IDI_START));
    ICONINFO iconInfo = { 0 };
    GetIconInfo(icon, &iconInfo);
    int iconWidth = iconInfo.xHotspot * 2;
    int iconHeight = iconInfo.yHotspot * 2;
    toolBarCtrl.SetBitmapSize(CSize(iconWidth, iconHeight));
    toolBarCtrl.SetButtonSize(CSize(iconWidth, iconHeight + iconHeight / 4));

    // 设置工具栏图片和按钮
    TBBUTTON tbButtons[] = {
        {0, IDC_BUTTON_START, TBSTATE_ENABLED, 0, 0, 0, 0},
        {1, IDC_BUTTON_PAUSE, 0, 0, 0, 0, 0},
        {2, IDC_BUTTON_MUSIC, TBSTATE_ENABLED, 0, 0, 0, 0},
        {3, IDC_BUTTON_HELP, TBSTATE_ENABLED, 0, 0, 0, 0},
    };
    int buttonCount = sizeof(tbButtons) / sizeof(TBBUTTON);
    CBitmap bitmap;
    bitmap.CreateCompatibleBitmap(CDialog::GetDC(), iconWidth * buttonCount, iconHeight);
    toolBarCtrl.AddBitmap(buttonCount, &bitmap);
    toolBarCtrl.AddButtons(buttonCount, tbButtons);

    // 设置工具栏按钮的图标
    CImageList* imageList = toolBarCtrl.GetImageList();
    CToolTipCtrl* toolTipCtrl = toolBarCtrl.GetToolTips();
    for (int i = 0; i < buttonCount; i++) {
        // 替换工具栏按钮的图标
        icon = LoadIcon(instance, MAKEINTRESOURCE(IDI_START + i));
        imageList->Replace(i, icon);
    }
    toolBarCtrl.SetImageList(imageList);

    // 设置工具栏按钮的提示文字
    toolTipCtrl->UpdateTipText(IDS_HELP, &mToolBar, IDC_BUTTON_HELP);
    toolTipCtrl->UpdateTipText(IDS_MUSIC, &mToolBar, IDC_BUTTON_MUSIC);
    toolTipCtrl->UpdateTipText(IDS_PAUSE, &mToolBar, IDC_BUTTON_PAUSE);
    toolTipCtrl->UpdateTipText(IDS_START, &mToolBar, IDC_BUTTON_START);

    // 注册工具栏
    CDialog::RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0);

    // 创建状态栏
    CRect rect;
    mStatusBar.Create(WS_CHILD | WS_VISIBLE | CCS_BOTTOM, rect, this, AFX_IDW_STATUS_BAR);

    // 设置状态栏上每格的宽度
    CDialog::GetWindowRect(rect);
    int parts[Const::STATUS_BAR_PART_COUNT] = {
        rect.Width() / 2, 
        rect.Width()
    };
    mStatusBar.SetParts(Const::STATUS_BAR_PART_COUNT, parts);

    // 设置状态栏上显示的文字
    CString text;
    text.LoadString(IDS_DIFFICULTY);
    mStatusBar.SetText(text, 0, 0);

    text.LoadString(IDS_SCORE);
    mStatusBar.SetText(text, 1, 0);

    // 创建游戏区域
    mToolBar.GetWindowRect(rect);
    CRect gameBoardRect(0, rect.Height() + 2, Const::GAME_BOARD_WIDTH, rect.Height() + 2 + Const::GAME_BOARD_HEIGHT);
    mGameBoard.Create(NULL, NULL, WS_CHILD | WS_VISIBLE, gameBoardRect, this, 0);

    // 创建游戏
    mGame = new Game(this, mGameBoard.GetDrawer(), &mGameBoard);

    return TRUE;
}

/**
 * 得分事件的响应方法。
 * @param wParam    得分
 */
LRESULT MainWindow::OnScore(WPARAM wParam, LPARAM) {
    CString text;
    CString score;
    text.LoadString(IDS_SCORE);
    score.Format(_T("%d"), wParam);
    text += score;
    mStatusBar.SetText(text, 2, 0);
    return 0;
}

/**
 * 定时器事件的响应方法。
 */
void MainWindow::OnTimer(UINT_PTR) {
    mGame->OnTimer();
}

/**
 * 在翻译事件之前调用的方法。
 * @param msg   事件
 * @return 事件在此被处理则返回 TRUE，否则返回 FALSE
 */
BOOL MainWindow::PreTranslateMessage(MSG* msg) {
    if (msg->message == WM_KEYDOWN) {
        mGame->OnKeyPressed(msg->wParam);
        return TRUE;
    }

    return CDialog::PreTranslateMessage(msg);
}
